#!/usr/bin/env python2.6
# -*- coding: utf-8 -*-
""" Interfaz con libSiUSBXp
"""

from bl_interface import *
import ctypes as c
import time

# Global para referir a libSiUSBXp
api = c.CDLL('./libSiUSBXp.so')
if api is None:
    raise ValueError('No se encuentra la librería libSiUSBXp.so')

## CheckRxQueue timeout (in ms)
## This timeout is used to expire waiting for data to arrive from device
## because the SI_CheckRxQueue function always returns SI_SUCCESS even after the
## device has been removed (in case of surprise removal).
USBX_CHECKRXQUEUE_TIMEOUT = 100


## Returns number of bytes in queue at the time of returning, which are at
## least expectedBytes, or 0 on error.
def WaitForDeviceRXQueue (deviceHandle, expectedBytes, timeout = USBX_CHECKRXQUEUE_TIMEOUT):
    global api
    numBytesInQueue = c.c_uint32(0)
    queueStatus = c.c_uint32(0)
    start_time = time.time()
    while (numBytesInQueue.value < expectedBytes) and ((time.time() - start_time) * 1000 < timeout):
        if (api.SI_CheckRXQueue(deviceHandle, c.byref(numBytesInQueue), c.byref(queueStatus)) != 0):
            return 0

    if numBytesInQueue.value < expectedBytes:
        return 0
    return numBytesInQueue.value


def GetDevNo():
    """Nro. de dispositivos usb conectados
    """
    global api
    
    ndev=c.c_int32(0)
    res=api.SI_GetNumDevices(c.byref(ndev))
    if api_res[res]=='SI_SUCCESS':
        return ndev.value
    else:
        return 0

def DevList(tipo):
    """Descripcion de cada dispositivo conectado
    """
    global api
    
    if tipo.find('nam')>=0 or tipo.find('nom')>=0:
        fdev=c.c_int(dev_str['SI_RETURN_LINK_NAME'])
    if tipo.find('descrip')>=0 or tipo.find('lista')>=0:
        fdev=c.c_int(dev_str['SI_RETURN_DESCRIPTION'])
    if tipo.find('vid')>=0:
        fdev=c.c_int(dev_str['SI_RETURN_VID'])
    if tipo.find('pid')>=0:
        fdev=c.c_int(dev_str['SI_RETURN_PID'])
            
#    lista=[]
    string=c.create_string_buffer(256)
    for dispo in range(GetDevNo()):
#        print dispo
        res=api.SI_GetProductString(dispo,c.byref(string),fdev)
#        print res
        if api_res[res]=='SI_SUCCESS':
            if string.value.find('USB API')>=0:
                return dispo
#            lista.append(string.value)
#            print string.value
#        else:
#            print res
    return -1

def Open(dev):
    """Abre un dispo usbXpress
    """
    global api
    handle=c.c_ulong(0)

    res=api.SI_Open(dev,c.byref(handle))
    
    if api_res[res]=='SI_SUCCESS':
                            # actualizo el estado del puerto
                            # fijo tiempos maximos de espera p/escribir y leer
                            # EN CERO : HACE que la lectura no se bloquee aunque
                            # puede no leer todos los bytes pedidos.
                            ## ver AN169_USBXpress_Programmers_Guide.pdf
        ReadTimeOut=0       # [mS] no bloqueo la lectura
        WriteTimeOut=500    # [mS] no bloqueo la escritura
        api.SI_SetTimeouts(ReadTimeOut, WriteTimeOut)

        # limpio buffers de transmision y recepcion
        api.SI_FlushBuffers(handle,0,0)         
        return True, handle.value
    else:
        return False, None

def Close(handle):
    """Cierra un dispo usbXpress
    """
    global api

    api.SI_FlushBuffers(handle,0,0)   ## limpio buffers
    if api_res[api.SI_Close(handle)]=='SI_SUCCESS':
        print 'Device closed'
        return 1
    else:
        return 0

def Write(handle, datos):
    """Escribe datos en el dispositivo usbXpress
    """
    buff=c.create_string_buffer(datos)
    bytes_to_write=c.c_int(len(datos))
    bytes_written=c.c_int(0)
    res=api.SI_Write(handle,c.byref(buff),bytes_to_write, c.byref(bytes_written))
    if api_res[res]=='SI_SUCCESS':
        return bytes_written.value
    else:
        return 0

def Read (handle, count = None):
    """ Lee datos de un dispositivo usbXpress. Si no se especifica count, lee
    todos los bytes disponibles. Si se lo especifica, lee count bytes o lanza
    excepcion.
    """
    bytes_en_cola = c.c_int(0)
    estado_cola = c.c_int(0)
    res = api.SI_CheckRXQueue(handle, c.byref(bytes_en_cola), c.byref(estado_cola))
    if api_res[res] != 'SI_SUCCESS':
        raise ValueError('No se pudo leer la cola')

    if bytes_en_cola.value > 0:
        if count != None:
            if count > bytes_en_cola.value:
                raise ValueError('No hay suficientes bytes en cola')
            bytes_a_leer = c.c_int(count)
        else:
            bytes_a_leer = bytes_en_cola

        bytes_read = c.c_int(0)
        buff = c.create_string_buffer(1024)
        res = api.SI_Read(handle, c.byref(buff), bytes_a_leer, c.byref(bytes_read))
        if api_res[res] != 'SI_SUCCESS':
            raise ValueError('No se pudo leer la cola')

        return buff.raw[0:bytes_read.value]

def WaitForRead (handle, count = None, timeout = USBX_CHECKRXQUEUE_TIMEOUT):
    if count != None:
        WaitForDeviceRXQueue(handle, count, timeout)
    return Read(handle, count)

